package org.kingtop.mybatis.kengen;

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.kingtop.cache.IRedisTemplate;
import org.kingtop.mybatis.persistence.metamodel.TableField;
import org.kingtop.mybatis.persistence.metamodel.TableInfo;

/**
 * 自增主键的工厂类
 *
 * @author 陈金波
 * @date 2018年1月4日 下午9:00:56
 * @Copyright: 2018 chen jinbo. All rights reserved.
 */
public class KeyGeneratorFactory {
	
	/**记录IP与workerId的关系*/
	private static final String ID_WORKER_HASH = "ID_WORKER_HASH";
	/**worker自增*/
	private static final String ID_WORKER_INCR = "ID_WORKER_INCR";
	/**数据与datacenterId的悬系*/
	private static final String ID_WORKER_DATAID_HASH = "ID_WORKER_DATAID_HASH";
	/**datacenterId自增*/
	private static final String ID_WORKER_DATAID_INCR = "ID_WORKER_DATAID_INCR";
	
	private static IRedisTemplate redisTemplate;

	/**
	 * 根据枚举获取自增主键
	 * 
	 * @author 陈金波
	 * @date 2018年1月4日 下午9:01:24
	 * @param keyGeneratorEnum
	 * @return
	 * @return T
	 */
	@SuppressWarnings("unchecked")
	public static <T extends KeyGenerator> T getKeyGeneratorByKey(TableInfo tableInfo) {
		KeyGeneratorEnum keyGeneratorEnum = tableInfo.getPkKey();
		TableField tableField = tableInfo.getPkField();
		if (keyGeneratorEnum == KeyGeneratorEnum.NO_KEY) {
			return (T) NoKeyGenerator.INSTANCE;
		}
		if (keyGeneratorEnum == KeyGeneratorEnum.JDBC3_KEY) {
			return (T) Jdbc3KeyGenerator.INSTANCE;
		}
		if (keyGeneratorEnum == KeyGeneratorEnum.REDIS_KEY) {
			String redisIncrementName = tableField.getParams().get(TableField.REDIS_KEY_PARAM_NAME);
			if (StringUtils.isBlank(redisIncrementName)) {
				return (T) RedisKeyGenerator.INSTANCE;
			} else {
				return (T) new RedisKeyGenerator(RedisKeyGenerator.INSTANCE.getRedisTemplate(), redisIncrementName);
			}
		}
		if(keyGeneratorEnum == KeyGeneratorEnum.SNOWFLAKE_KEY) {
			return getIdWorker(tableInfo);
		}
		return (T) Jdbc3KeyGenerator.INSTANCE;
	}
	
	/**
	 * 获取IdWorkerKeyGenerator
	 * @author 陈金波  
	 * @date   2018年1月16日 下午9:33:04  
	 * @param tableInfo
	 * @return
	 * @return T
	 */
	@SuppressWarnings("unchecked")
	protected static <T extends KeyGenerator> T getIdWorker(TableInfo tableInfo) {
		IdWorkerKeyGenerator idWorkerKeyGenerator = null;
		long workerId = 0L;
		long datacenterId = 0L;
		
		if(redisTemplate != null) {
			try {
				String hostAddress = InetAddress.getLocalHost().getHostAddress();//只适合window使用,linux获取有问题
				
				String identifier = redisTemplate.acquireLockWithTimeout(hostAddress, 10, 10);
				if(redisTemplate.hexists(ID_WORKER_HASH, hostAddress)) {
					workerId = Long.parseLong(redisTemplate.hget(ID_WORKER_HASH, hostAddress));
				}else {
					workerId = redisTemplate.incr(ID_WORKER_INCR);
					redisTemplate.hset(ID_WORKER_HASH, hostAddress, String.valueOf(workerId));
				}
				
				if(redisTemplate.hexists(ID_WORKER_DATAID_HASH, hostAddress + tableInfo.getTableName())) {
					datacenterId = Long.parseLong(redisTemplate.hget(ID_WORKER_DATAID_HASH, hostAddress + tableInfo.getTableName()));
				}else {
					datacenterId = redisTemplate.incr(ID_WORKER_DATAID_INCR + hostAddress);
					redisTemplate.hset(ID_WORKER_DATAID_HASH, hostAddress + tableInfo.getTableName(), String.valueOf(datacenterId));
				}
				
				redisTemplate.releaseLock(hostAddress, identifier);
			} catch (UnknownHostException e) {
				e.printStackTrace();
			}
		}
		if(idWorkerKeyGenerator == null) {
			idWorkerKeyGenerator = new IdWorkerKeyGenerator(workerId, datacenterId);
		}
		return (T) idWorkerKeyGenerator;
	}

	/**
	 * @return the redisTemplate
	 */
	public static IRedisTemplate getRedisTemplate() {
		return redisTemplate;
	}

	/**
	 * @param redisTemplate the redisTemplate to set
	 */
	public static void setRedisTemplate(IRedisTemplate redisTemplate) {
		KeyGeneratorFactory.redisTemplate = redisTemplate;
	}

}
